/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>

#include "assembler/assembly-emitter.h"
#include "assembler/assembly-function.h"
#include "assembler/assembly-parser.h"
#include "assembler/assembly-program.h"
#include "codegen.h"
#include "compiler/optimizer/optimizations/cleanup.h"
#include "compiler/optimizer/optimizations/lowering.h"
#include "compiler/optimizer/optimizations/regalloc/reg_alloc_linear_scan.h"
#include "optimize_bytecode.h"
#include "tests/common.h"

namespace ark::bytecodeopt::test {

TEST_F(CommonTest, CodegenEcmaInt)
{
    auto graph = CreateEmptyGraph();
    graph->SetDynamicMethod();
    GRAPH(graph)
    {
        CONSTANT(0, 0).i32();

        BASIC_BLOCK(2, -1)
        {
            INST(1, Opcode::CastValueToAnyType).any().AnyType(compiler::AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0);
            INST(2, Opcode::Return).any().Inputs(1);
        }
    }

    EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
    auto function = pandasm::Function(std::string(), ark::panda_file::SourceLang::ECMASCRIPT);
    EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, nullptr));
}

TEST_F(CommonTest, CodegenEcmaDouble)
{
    auto graph = CreateEmptyGraph();
    graph->SetDynamicMethod();
    GRAPH(graph)
    {
        CONSTANT(0, 0).f64();

        BASIC_BLOCK(2, -1)
        {
            INST(1, Opcode::CastValueToAnyType).any().AnyType(compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0);
            INST(2, Opcode::Return).any().Inputs(1);
        }
    }

    EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
    auto function = pandasm::Function(std::string(), ark::panda_file::SourceLang::ECMASCRIPT);
    EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, nullptr));
}

TEST_F(CommonTest, CodegenEcmaTaggedUndefined)
{
    auto graph = CreateEmptyGraph();
    graph->SetDynamicMethod();
    GRAPH(graph)
    {
        CONSTANT(0, 0).i32();

        BASIC_BLOCK(2, -1)
        {
            INST(1, Opcode::CastValueToAnyType)
                .any()
                .AnyType(compiler::AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE)
                .Inputs(0);
            INST(2, Opcode::Return).any().Inputs(1);
        }
    }

    EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
    auto function = pandasm::Function(std::string(), ark::panda_file::SourceLang::ECMASCRIPT);
    EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, nullptr));
}

TEST_F(CommonTest, CodegenEcmaTaggedTrue)
{
    auto graph = CreateEmptyGraph();
    graph->SetDynamicMethod();
    GRAPH(graph)
    {
        CONSTANT(0, 1).i64();

        BASIC_BLOCK(2, -1)
        {
            INST(1, Opcode::CastValueToAnyType).any().AnyType(compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE).Inputs(0);
            INST(2, Opcode::Return).any().Inputs(1);
        }
    }

    EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
    auto function = pandasm::Function(std::string(), ark::panda_file::SourceLang::ECMASCRIPT);
    EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, nullptr));
}

TEST_F(CommonTest, CodegenEcma_jtrue)
{
    auto graph = CreateEmptyGraph();
    graph->SetDynamicMethod();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        CONSTANT(1, 1).i64();

        BASIC_BLOCK(2, 3, 4)
        {
            INST(2, Opcode::CastValueToAnyType).any().AnyType(compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE).Inputs(1);
            INST(3, Opcode::If).SrcType(compiler::DataType::ANY).CC(compiler::CC_EQ).Inputs(0, 2);
        }
        BASIC_BLOCK(3, -1)
        {
            INST(4, Opcode::Return).any().Inputs(0);
        }
        BASIC_BLOCK(4, -1)
        {
            INST(5, Opcode::Return).any().Inputs(2);
        }
    }

    EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
    auto function = pandasm::Function(std::string(), ark::panda_file::SourceLang::ECMASCRIPT);
    EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, nullptr));
}

}  // namespace ark::bytecodeopt::test

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
